/*
 * Copyright (c) 2018-2024 北京华恒盛世科技有限公司
 * QUICKPOOL is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
*/

#include "subcmd.h"

static void jobdepend_usage(const char *);

/**
 * @brief       qp job dep handler, to query job dependency in the cluster.
 *
 * @param[in]   argc          #1: number of input argument
 * @param[in]   argv          #2: string array of the input argument
 *
 * @retval      0             #1: succeed
 * @retval      1             #2: input option is wrong or kind of input argument not specified
 * @retval      2             #3: argument has syntax error
 * @retval      3             #4: failed to query job dependency in the cluster
 * @retval      4             #5: not enough memory to print json string
 */
int
cmd_job_dependency(int argc, char **argv)
{
    while (TRUE) {
        int option_index = 0;
        static struct option long_options[] = {
            {"help", no_argument, 0, 'h'},
            {NULL, 0, 0, 0}
        };

        int opt;
        opt = getopt_long(argc, argv, "h", long_options, &option_index);
        if (-1 == opt) {
            break;
        }

        switch (opt) {
        case 'h':
            jobdepend_usage(argv[0]);
            exit(0);
        case '?':
        default:
            jobdepend_usage(argv[0]);
            exit(1);
	}
    }

    if (argc <= optind) {
        fprintf(stderr, "Must specify a job ID.\n");
        jobdepend_usage(argv[0]);
        exit(1);
    }

    // get the job ID for querying its dependency.
    JOBID_T jobId;
    if (get_one_jobid(argv[argc - 1], &jobId)) {
        exit(2);
    }

    struct request jobdepRequest;
    memset(&jobdepRequest, 0, sizeof(struct request));

    jobdepRequest.number = 1;
    jobdepRequest.keyvalues = (struct keyvalue *)calloc(jobdepRequest.number,
                                                         sizeof(struct keyvalue));
    if (NULL == jobdepRequest.keyvalues) {
        fprintf(stderr, "calloc(%ld) failed due to %m.\n",
                jobdepRequest.number*sizeof(struct keyvalue));
        exit(4);
    }

    jobdepRequest.keyvalues[0].key = REQUEST_KEY_JOBIDS;
    jobdepRequest.keyvalues[0].value = (char *)calloc(32, sizeof(char));
    if (NULL == jobdepRequest.keyvalues[0].value) {
        fprintf(stderr, "calloc(%d) failed due to %m.\n", 32);
        exit(4);
    }
    snprintf(jobdepRequest.keyvalues[0].value, 32, "%lld", jobId);

    struct QuickPoolJobDepReply *jobdepReply;
    jobdepReply = client_get_jobdependency(&jobdepRequest, NULL);
    if (quickpool_errno != 0 || NULL == jobdepReply) {

        if (NULL != jobdepReply) {
            // JS replied error message.
            fprintf(stderr, "%s\n", jobdepReply->error_message);

            gf_xdr_free(libxdr_jobdep_reply, jobdepReply);
            FREEUP(jobdepReply);
        } else {
            fprintf(stderr, "Fail to query job dependency due to above error.\n");
        }

        gf_xdr_free(gf_xdr_request, &jobdepRequest);

	exit(3);
    }

    gf_xdr_free(gf_xdr_request, &jobdepRequest);

    if (0 == jobdepReply->num_dependency) {
        char strJobId[32];
        fprintf(stderr, "Job <%s> dependency not found.\n",
                jobid_2string(jobId, strJobId));

        gf_xdr_free(libxdr_jobdep_reply, jobdepReply);
        FREEUP(jobdepReply);

        exit(0);
    }

    json *jsonDepend = json_CreateObject();
    json_AddNumberToObject(jsonDepend, "JOBID", ARRAY_JOBID(jobId));
    if (0 < ARRAY_INDEX(jobId)) {
        json_AddNumberToObject(jsonDepend, "JOB_INDEX", ARRAY_INDEX(jobId));
    }

    unsigned int i;
    for (i=0; i<jobdepReply->num_dependency; i++) {
        json *jsonDep = json_CreateObject();

        json_AddStringToObject(jsonDep, "CONDITION", jobdepReply->dependencies[i].dependency);
        json_AddStringToObject(jsonDep, "DEPEND_JOBID", jobdepReply->dependencies[i].jobid);

        char *strStatus;
        if (IS_JOB_PENDING(jobdepReply->dependencies[i].jstatus)) {
            strStatus = (char *)"PEND";
        } else if (IS_JOB_STARTED(jobdepReply->dependencies[i].jstatus)) {
            strStatus = (char *)"STARTED";
        } else if (jobdepReply->dependencies[i].jstatus & JOB_STATUS_DONE) {
            strStatus = (char *)"DONE";
        } else if (jobdepReply->dependencies[i].jstatus & JOB_STATUS_EXIT) {
            strStatus = (char *)"EXIT";
        } else {
            strStatus = (char *)"UNKNOWN";
        }
        json_AddStringToObject(jsonDep, "JOB_STATUS", strStatus);

        if (jobdepReply->dependencies[i].depstatus) {
            json_AddTrueToObject(jsonDep, "DEPENDENCY_STATUS");
        } else {
            json_AddFalseToObject(jsonDep, "DEPENDENCY_STATUS");
        }

        json_AddItemToObject(jsonDepend, "DEPENDENCY", jsonDep);
    }

    char *strJson;
    strJson = json_Print(jsonDepend);
    if (NULL != strJson) {
        fprintf(stdout, "%s\n", strJson);
        FREEUP(strJson);
    } else {

        perror("malloc");
        json_Delete(jsonDepend);
        gf_xdr_free(libxdr_jobdep_reply, jobdepReply);
        FREEUP(jobdepReply);

        exit(4);
    }
    json_Delete(jsonDepend);

    gf_xdr_free(libxdr_jobdep_reply, jobdepReply);
    FREEUP(jobdepReply);

    exit(0);
} // end function cmd_job_dependency

static void
jobdepend_usage(const char *cmd)
{
    fprintf(stdout, "qp job %s usage: [-h, help] jobId\n", cmd);

    return;
}
